package mhe.mgt.detail;

import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.List;

import mhe.mgt.Activator;
import mhe.mgt.Application;
import mhe.mgt.NavigationView;
import mhe.mgt.model.MchMachine;
import mhe.mgt.model.MchMachinePart;
import mhe.mgt.util.DateUtils;

import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.ISharedImages;

public class DetailTable extends TableViewer implements Listener {

	protected static final int COLUMN_NAME = 0;
	protected static final int COLUMN_CREATE_DATE = 1;
	protected static final int COLUMN_UPDATE_DATE = 2;
	protected static final int COLUMN_MAX_LIFE_DAY = 3;
	protected static final int COLUMN_REMAIN_DAY = 4;
	protected static final int COLUMN_EXPIRED_DAY = 5;
	protected static final int COLUMN_REMAIN_IMAGE = 6;
	private MchMachine machine;
	public static DetailTable instance;
	private boolean showImage = false;
	DecimalFormat nf = new DecimalFormat(Messages.DetailTable_0);

	public DetailTable(Composite parent) {
		super(parent, SWT.FULL_SELECTION | SWT.BORDER);
		instance = this;
		initBody();
	}

	private void initBody() {
		final Table table = this.getTable();

		TableColumn tc = new TableColumn(table, SWT.LEFT);
		tc.setText(Messages.DetailTable_1);
		tc.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				((ItemViewerSorter) DetailTable.this.getSorter())
						.doSort(COLUMN_NAME);
				DetailTable.this.refresh();
			}
		});

		tc = new TableColumn(table, SWT.CENTER);
		tc.setText(Messages.DetailTable_2);
		tc.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				((ItemViewerSorter) DetailTable.this.getSorter())
						.doSort(COLUMN_CREATE_DATE);
				DetailTable.this.refresh();
			}
		});

		tc = new TableColumn(table, SWT.CENTER);
		tc.setText(Messages.DetailTable_3);
		tc.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				((ItemViewerSorter) DetailTable.this.getSorter())
						.doSort(COLUMN_UPDATE_DATE);
				DetailTable.this.refresh();
			}
		});

		tc = new TableColumn(table, SWT.RIGHT);
		tc.setText(Messages.DetailTable_4);
		tc.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				((ItemViewerSorter) DetailTable.this.getSorter())
						.doSort(COLUMN_MAX_LIFE_DAY);
				DetailTable.this.refresh();
			}
		});

		tc = new TableColumn(table, SWT.RIGHT);
		tc.setText(Messages.DetailTable_5);
		tc.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				((ItemViewerSorter) DetailTable.this.getSorter())
						.doSort(COLUMN_REMAIN_DAY);
				DetailTable.this.refresh();
			}
		});

		tc = new TableColumn(table, SWT.CENTER);
		tc.setText(Messages.DetailTable_6);
		tc.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				((ItemViewerSorter) DetailTable.this.getSorter())
						.doSort(COLUMN_EXPIRED_DAY);
				DetailTable.this.refresh();
			}
		});

		tc = new TableColumn(table, SWT.CENTER);
		tc.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				((ItemViewerSorter) DetailTable.this.getSorter())
				.doSort(COLUMN_REMAIN_IMAGE);
				DetailTable.this.refresh();
			}
		});
		
		for (int i = 0, n = table.getColumnCount(); i < n; i++) {
			table.getColumn(i).setWidth(140);
		}

		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		setContentProvider(new ItemContentProvider());
		setLabelProvider(new ItemLabelProvider());
		setSorter(new ItemViewerSorter());

		NavigationView.addSelectionListener(this);
		
		addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
				// if the selection is empty clear the label
				if (event.getSelection().isEmpty()) {
					return;
				}
				if (event.getSelection() instanceof IStructuredSelection) {
					IStructuredSelection selection = (IStructuredSelection) event
							.getSelection();
					if (!selection.isEmpty()) {
						Event e = new Event();
						e.data = selection.getFirstElement();
						DetailForm.instance.handleEvent(e);
					}
				}
			}
		});
		
		table.addListener(SWT.PaintItem, new Listener() {
			public void handleEvent(Event e) {
				int colIndex = e.index;
				if (COLUMN_REMAIN_IMAGE == colIndex) {
					if (e.item.getData() instanceof MchMachinePart) {
						Color fc = e.gc.getForeground();
						Color bc = e.gc.getBackground();
						MchMachinePart p = (MchMachinePart) e.item.getData();
						Color c;
						float rate = p.getRemainRate();
						if (rate >= 0.666) {
							c = table.getDisplay().getSystemColor(SWT.COLOR_BLUE);
						} else if (rate >= 0.333) {
							c = table.getDisplay().getSystemColor(SWT.COLOR_YELLOW);
						} else {
							c = table.getDisplay().getSystemColor(SWT.COLOR_RED);
						}
						e.gc.setForeground(c);
						e.gc.setBackground(c);
						int w = table.getColumn(colIndex).getWidth() - 4;
						int h = e.height - 8;
						e.gc.drawRectangle(e.x + 1, e.y + 4, w, h);
						w = (int) (w * rate);
						e.gc.fillRectangle(e.x + 1, e.y + 4, w, h);
						e.gc.setForeground(fc);
						e.gc.setBackground(bc);
						
						//((TableItem)e.item).setText(colIndex, nf.format(p.getRemainRate() * 100) + "%");
					}
				}
			}
		});
		
		setInput(Application.machinePartService.list().toArray());

		if (showImage) {
			setInput(ISharedImages.class.getDeclaredFields());
		}
	}

	class ItemContentProvider implements IStructuredContentProvider {

		/**
		 * Gets the elements for the table
		 * 
		 * @param arg0
		 *            the model
		 * @return Object[]
		 */
		public Object[] getElements(Object model) {
			
			return (Object[]) model;
		}

		/**
		 * Disposes any resources
		 */
		public void dispose() {
			// We don't create any resources, so we don't dispose any
		}

		/**
		 * Called when the input changes
		 * 
		 * @param arg0
		 *            the parent viewer
		 * @param arg1
		 *            the old input
		 * @param arg2
		 *            the new input
		 */
		public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
			// Nothing to do
		}
	}

	class ItemLabelProvider implements ITableLabelProvider {

		public ItemLabelProvider() {
		}

		/**
		 * Gets the image for the specified column
		 * 
		 * @param arg0
		 *            the player
		 * @param arg1
		 *            the column
		 * @return Image
		 */
		Image image = Application.getImage(ISharedImages.IMG_ELCL_SYNCED);

		public Image getColumnImage(Object obj, int colIndex) {
			if (showImage) {
				Image image = null;
				if (colIndex == 0) {
					try {
						image = Application.getImage(((Field) obj).get(
								ISharedImages.class).toString());
					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
				return image;
			}
			if (colIndex == COLUMN_NAME) {
				return image;
			}
			return null;
		}

		/**
		 * Gets the text for the specified column
		 * 
		 * @param obj
		 *            the player
		 * @param colIndex
		 *            the column
		 * @return String
		 */
		public String getColumnText(Object obj, int colIndex) {
			if (showImage) {
				String text = Messages.DetailTable_7;
				if (colIndex == 1) {
					text = ((Field) obj).getName();
				}
				return text;
			}
			MchMachinePart p = (MchMachinePart) obj;
			String text = Messages.DetailTable_8;
			switch (colIndex) {
			case COLUMN_NAME:
				text = p.getName();
				break;
			case COLUMN_CREATE_DATE:
				text = DateUtils.formatDateTime(p.getCreateDate());
				break;
			case COLUMN_UPDATE_DATE:
				text = DateUtils.formatDateTime(p.getUpdateDate());
				break;
			case COLUMN_EXPIRED_DAY:
				text = DateUtils.formatDateTime(p.getExpiredDate());
				break;
			case COLUMN_REMAIN_DAY:
				text = nf.format(p.getRemainDay()) + Messages.DetailTable_9 + nf.format(p.getRemainRate() * 100) + Messages.DetailTable_10;
				break;
			case COLUMN_MAX_LIFE_DAY:
				text = nf.format(p.getMaxLifeDay());
				break;
			}
			return text;
		}
		
		/**
		 * Adds a listener
		 * 
		 * @param arg0
		 *            the listener
		 */
		public void addListener(ILabelProviderListener arg0) {
			// Throw it away
		}

		/**
		 * Dispose any created resources
		 */
		public void dispose() {
		}

		/**
		 * Returns whether the specified property, if changed, would affect the
		 * label
		 * 
		 * @param arg0
		 *            the player
		 * @param arg1
		 *            the property
		 * @return boolean
		 */
		public boolean isLabelProperty(Object arg0, String arg1) {
			return false;
		}

		/**
		 * Removes the specified listener
		 * 
		 * @param arg0
		 *            the listener
		 */
		public void removeListener(ILabelProviderListener arg0) {
			// Do nothing
		}
	}

	class ItemViewerSorter extends ViewerSorter {
		private static final int ASCENDING = 0;

		private static final int DESCENDING = 1;

		private int column;

		private int direction;

		/**
		 * Does the sort. If it's a different column from the previous sort, do
		 * an ascending sort. If it's the same column as the last sort, toggle
		 * the sort direction.
		 * 
		 * @param column
		 */
		Image up = Activator.getImageDescriptor("icons/up.png").createImage();
		Image down = Activator.getImageDescriptor("icons/down.png").createImage();
		public void doSort(int column) {
			if (column == this.column) {
				// Same column as last sort; toggle the direction
				direction = 1 - direction;
			} else {
				// New column; do an ascending sort
				this.column = column;
				direction = ASCENDING;
			}
			Image image = up;
			if (direction == ASCENDING) {
				image = down;
			}
			for (TableColumn cl : getTable().getColumns()) {
				if (cl.getImage() != null) {
					cl.setImage(null);
				}
			}
			getTable().getColumn(this.column).setImage(image);
		}

		/**
		 * Compares the object for sorting
		 */
		public int compare(Viewer viewer, Object e1, Object e2) {
			int rc = 0;
			if (showImage) {
				return rc;
			}
			
			MchMachinePart p1 = (MchMachinePart) e1;
			MchMachinePart p2 = (MchMachinePart) e2;

			// Determine which column and do the appropriate sort switch
			switch (column) {
			case COLUMN_NAME:
				rc = p1.getName().compareToIgnoreCase(p2.getName());
				break;
			case COLUMN_CREATE_DATE:
				rc = p1.getCreateDate().compareTo(p2.getCreateDate());
				break;
			case COLUMN_UPDATE_DATE:
				rc = p1.getUpdateDate().compareTo(p2.getUpdateDate());
				break;
			case COLUMN_MAX_LIFE_DAY:
				rc = p1.getMaxLifeDay() - p2.getMaxLifeDay();
				break;
			case COLUMN_REMAIN_DAY:
				rc = p1.getRemainDay() - p2.getRemainDay();
				break;
			case COLUMN_EXPIRED_DAY:
				rc = p1.getExpiredDate().compareTo(p2.getExpiredDate());
				break;
			case COLUMN_REMAIN_IMAGE:
				rc = p1.getRemainRate() > p2.getRemainRate() ? 1 : -1;
				break;
			}

			// If descending order, flip the direction
			if (direction == DESCENDING)
				rc = -rc;

			return rc;
		}
	}

	@Override
	public void handleEvent(Event event) {
		Object obj = event.data;
		machine = null;
		if (obj != null && obj instanceof MchMachine) {
			machine = (MchMachine) obj;

			refreshTable();
		}
	}
	
	private Object[] getAllPart() {
		if (machine == null) {
			return null;
		}
		return Application.machinePartService.list(
				new String[] { Messages.DetailTable_11 },
				new Object[] { machine.getId() }, false, null, -1, -1)
				.toArray();
	}

	public void searchItem(String text) {
		List<MchMachinePart> list = Application.machinePartService.searchByText(text);
		setInput(list.toArray());
		super.refresh();
	}

	public void refreshTable() {
		setInput(getAllPart());
		for (TableColumn cl : getTable().getColumns()) {
			if (cl.getImage() != null) {
				cl.setImage(null);
			}
		}
		refresh();
	}
}